#include<stdio.h>
#include<string.h>
#include<stdlib.h>

// @动态数组


//动态数组结构体
struct dynamicArray{
    void ** pAddr; // 维护真实在堆区创建的数组指针
    int m_capacity; //数组容量
    int m_size; //数组的大小
};

//1初始化数组
struct dynamicArray * init_DynamicArray(int capacity){
    if (capacity <= 0){
        return NULL;
    }

    // 给数组分配空间
    struct dynamicArray * array = malloc(sizeof(struct dynamicArray));
    if (array == NULL){
        return NULL;
    }

    //给数组初始化
    array->pAddr = malloc(sizeof(void *) * capacity);
    array->m_capacity = capacity;
    array->m_size = 0;

    return array;
}

//2插入数组
/**
 * @array 动态数组指针
 * @pos 插入的位置
 * @data 插入的数据
 */
void insert_DynamicArray(struct dynamicArray *array, int pos, void * data){
    if(array==NULL){
        return;
    }
    if (data == NULL){
        return;
    }

    // 无效位置 尾插
    if ( pos<0 || pos > array->m_size ){
        pos = array->m_size;
    }

    //判断是否满了，如果已经满了 动态扩展(capcity变大)
    if (array->m_size == array->m_capacity){
        //计算新空间
        int newCapacity = array->m_capacity *2;

        //创建新空间
        void ** newSpace = malloc(sizeof(void*) * newCapacity);

        // 将原有数据拷贝到新空间下
        memcpy(newSpace, array->pAddr,sizeof(void *) * array->m_capacity);

        //释放原有内存空间
        free(array->pAddr);

        //更新新空间指向
        array->pAddr = newSpace;

        //更新新容量
        array->m_capacity = newCapacity;  
    }

    //**** 插入新元素
    // 移动元素 插入新元素
    for(int i=array->m_size-1;i>=pos;i--){
        //数据向后移动
        array->pAddr[i+1] = array->pAddr[i];
    }

    //将新元素 插入到指定的位置上
    array->pAddr[pos] = data;
    // 更新大小
    array->m_size++;

}

//3遍历数组
void foreach_DynamicArray( struct dynamicArray*array, void(*myPrint)(void *) ){
    if (array== NULL){
        return ;
    }

    if(myPrint == NULL){
        return;
    }

    for (int i=0;i<array->m_size;i++){
        //不知道什么类型，将地址给用户，用户自己决定怎么打印
        myPrint(array->pAddr[i]);
    }
}

//4按位置删除
void delByPos_DynamicArray(struct dynamicArray*array, int pos){
    if(array == NULL){
        return;
    }

    if(pos<0 || pos>array->m_size-1){
        return;
    }

    // 数据前移
    for(int i=pos;i<array->m_size-1;i++){
        array->pAddr[i] = array->pAddr[i+1];
    }
    //更新数组的大小
    array->m_size--;
}

// 按值删除
void delByVal_DynamicArray(struct dynamicArray* array, void * data, void(*myCompare)(void * ,void *)){
    if (NULL == array){
        return;
    }
    if(NULL==data){
        return;
    }
    for(int i=0;i<array-m_size;i++){
        // 如何对比  用户决定
        if(myCompare(array->pAddr[i], data)){
            // 如果找到要删除的数据，i就是要删除的具体位置
            delByPos_DynamicArray(array, i);
        }
    }
}

//5 销毁
void destroy_DynamicArray(struct dynamicArray*array){
    if(array==NULL){
        return;
    }

    if(array->pAddr!=NULL){
        free(array->pAddr);
        array->pAddr = NULL;
    }

    free(array);
    array=NULL;
}

//*************************************************************
//4测试
struct Person{
    char name[64];
    int age;
};


void myPrintPerson(void *data){
    struct Person *p = data;
    printf("姓名:%s  年龄:%d\n", p->name, p->age);
}

int myCompare(void * data1,void * data2){
    struct Person * p1 = data1;
    struct Person * p2 = data2;
    if(data1.name == data2.name){
        return 1;
    }

    return 0;
}


int main(){

    //初始化动态数组
    struct dynamicArray * array = init_DynamicArray(5);

    // 准备数据
    struct Person p1 = {"小徐", 18};
    struct Person p2 = {"小李", 20};
    struct Person p3 = {"小刘", 21};
    struct Person p4 = {"小王", 23};
    struct Person p5 = {"小黑", 22};
    struct Person p6 = {"小田", 17};

    printf("插入数据前 容量:%d  大小:%d \n", array->m_capacity, array->m_size);

    // 插入数据
    insert_DynamicArray(array, 0, &p1);
    insert_DynamicArray(array, -1, &p2);
    insert_DynamicArray(array, 1, &p3);
    insert_DynamicArray(array, 0, &p4);
    insert_DynamicArray(array, 2, &p5);
    insert_DynamicArray(array, 0, &p6);

    // 遍历数据
    foreach_DynamicArray(array, myPrintPerson);

    printf("容量:%d  大小:%d \n", array->m_capacity, array->m_size);

   

    return 0;
}